package bupt.xixi.netty;

import bupt.xixi.entity.RequestHandler;
import bupt.xixi.entity.RpcRequest;
import bupt.xixi.entity.RpcResponse;
import bupt.xixi.registry.IServiceRegistry;
import bupt.xixi.registry.impl.AbstractRegistry;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class NettyServerHandler extends SimpleChannelInboundHandler<RpcRequest> {

    private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);

    private final IServiceRegistry serviceRegistry;
    private final RequestHandler requestHandler;

    public NettyServerHandler(IServiceRegistry register, RequestHandler requestHandler) {
        this.serviceRegistry = register;
        this.requestHandler = requestHandler;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext context, RpcRequest rpcRequest) throws Exception {
        try {
            logger.info("服务器接受到请求： {}", rpcRequest);
            // 获得接口名
             String interfaceName = rpcRequest.getInterfaceName();
            // 找到服务
            Object service = this.serviceRegistry.getService(interfaceName);
            // 求结果
            Object result = this.requestHandler.handle(rpcRequest, service);
            // 在Inbound执行write后，outbound执行顺序为out1<-out2<-write
            ChannelFuture future = context.writeAndFlush(RpcResponse.success(result));
            future.addListener(ChannelFutureListener.CLOSE); // 当检测完所有包都发送成功后关闭通道
        } finally {
            // todo: 这种结束方法的特点是啥？
            ReferenceCountUtil.release(rpcRequest);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            // 如果在规定时间内没收到PONG, 可以拜拜了宁嘞
            logger.info("太长时间没收到客户端发来的PING了, 要关闭连接啦");
            if(event.state().equals(IdleState.READER_IDLE)) {
                ctx.channel().close();
            }
        }
    }
}
